﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;
using ARchGL.Declaration.Platform.Domain.Entities;
using ARchGL.Declaration.Platform.Service.Dtos;
using ARchGL.Declaration.Platform.Service.Utils;
using TDF.Core.Configuration;
using TDF.Core.Exceptions;
using TDF.Core.Ioc;
using TDF.Core.Models;
using TDF.Core.Operator;
using TDF.Data.Repository;

namespace ARchGL.Declaration.Platform.Service
{
    /// <summary>
    /// 系统服务
    /// </summary>
    public class SystemService : BaseService, ISystemService
    {
        #region 用户相关

        ///登录
        public AccountDto Login(string name, string password)
        {
            using (var repository = Ioc.Resolve<IRepositoryBase<Account>>())
            {
                var number = name.Trim().Replace("\t", "");
                if (number.IsNullOrWhiteSpace())
                    throw new KnownException("账户不存在，请重新输入或联系质监员创建");

                var entity = repository.FindEntity(x => x.Number == number || x.PhoneNumber == number);
                if (entity.IsNull())
                {
                    throw new KnownException("账户不存在，请重新输入或联系质监员创建");
                }
                if(entity.Status == 2)
                    throw new KnownException("账户已停用，请重新输入或联系管理员启用");
                if (password.ToMD5() != entity.Password && SystemHelper.GetFirstMacAddress() != "E03F490F2A77")//开发机调试时不验证密码
                {
                    AddLogging(entity, LoginStatus.失败, "密码不正确");//记录登录日志
                    throw new KnownException("密码不正确，请重新输入或联系质监员重置");
                }
                var dto = entity.Merge<Account, AccountDto>();
                var oper = BuildOperator(entity);
                dto.Lastlogintime = GetLastlogintimeByAccountId(entity.Id);//最后登录时间赋值
                dto.LoginToken = oper.LoginToken;
                dto.HasChangePassword = entity.Number.ToMD5() != entity.Password;
                AddLogging(entity, LoginStatus.成功);//记录登录日志
                AddSession(dto);//记录 Session
                return dto;
            }
        }

        ///保存登录信息
        private void AddSession(AccountDto dto)
        {
            try
            {
                using (var repository = Ioc.Resolve<IRepositoryBase<Sys_Session>>())
                {
                    var context = HttpContext.Current;
                    var authorization = context.Request.Headers["Authorization"] ?? string.Empty;
                    var session = new Sys_Session
                    {
                        Id = Guid.NewGuid(),
                        AccountId = dto.Id,
                        AccountName = dto.Name,
                        Number = dto.Number,
                        Token = dto.LoginToken,
                        Type = dto.Type,
                        ExpiredTime = DateTime.Now.AddDays(7),
                        Roles = dto.Roles,
                        Authorization = authorization,
                        CreatedTime = DateTime.Now,
                    };
                    repository.Insert(session);
                }
            }
            catch (Exception)
            {
            }
        }

        ///根据账户Id查询账户信息
        public AccountDto GetAccountById(Guid id)
        {
            using (var repository = Ioc.Resolve<IRepositoryBase<Account>>())
            {
                var entity = repository.FindEntity(id);
                if (entity.IsNull()) throw new KnownException("帐号不存在");
                return entity.Merge<Account, AccountDto>();
            }
        }

        ///返回当前区县下最大质监员编号
        public int GetAccountMaxNumber()
        {
            if (CurrentSession.Type != AccountType.区县帐号)
                throw new KnownException("当前用户没有权限访问该接口");

            using (var repository = Ioc.Resolve<IRepositoryBase<Account>>())
            {
                var entity = repository.IQueryable().OrderByDescending(x => x.Number)
                    .FirstOrDefault(x => x.Type == AccountType.质监员帐号 && x.AccountIds.Contains(CurrentSession.AccountId.ToString()));
                if (entity.IsNull()) return 1;

                var number = entity.Number.Replace(CurrentSession.Number, "");
                if (number.IsNullOrWhiteSpace()) return 1;

                return int.Parse(number) + 1;
            }
        }

        private static IPagedList<AccountDto> companyList = null;//新增企业帐号会清空缓存

        ///获取企业帐号缓存数据
        public IPagedList<AccountDto> GetCompanyCacheAccountList()
        {
            if (companyList != null) return companyList;

            using (var repository = Ioc.Resolve<IRepositoryBase<Account>>())
            {
                return companyList = repository.IQueryable().WhereByType(AccountType.企业帐号)
                    .ToDto()
                    .OrderByDescending(x => x.CreatedTime)
                    .ToPageResult1(1, 5000);
            }
        }

        ///获取企业帐号-分页数据集合
        public Tuple<int, IPagedList<CompanyAccountDto>> GetCompanyAccountPagedList(AccountCriteria criteria)
        {
            using (var repository = Ioc.Resolve<IRepositoryBase>())
            {
                criteria.Type = AccountType.企业帐号;
                var result = repository.IQueryable<Account>()
                    .WhereByAccountIds(criteria.AccountId)
                    .WhereByKeywords(criteria?.Keywords?.Trim())
                    .WhereByStatus(criteria.Status)
                    .WhereByType(criteria.Type)
                    .ToCompanyAccountDto()
                    .OrderByDescending(x => x.CreatedTime)
                    .ToPageResult1(criteria.PageIndex, criteria.PageSize);

                var idList = result.Rows.Select(x => x.Id.ToString()).ToList();

                var projectList = repository.IQueryable<DP_Project>().WhereByBuilderUnitIdList(idList);

                foreach (var item in result.Rows)
                {
                    item.ProjectCount = projectList.Count(x => x.BuilderUnitIds.Contains(item.Id.ToString()));
                }

                return new Tuple<int, IPagedList<CompanyAccountDto>>(GetAccountCountByType(criteria, repository), result);
            }
        }

        ///获取区县帐号-分页数据集合
        public Tuple<int, IPagedList<AreaAccountDto>> GetAreaAccountPagedList(AccountCriteria criteria)
        {
            using (var repository = Ioc.Resolve<IRepositoryBase>())
            {
                criteria.Type = AccountType.区县帐号;
                var result = repository.IQueryable<Account>()
                   //.WhereByAccountIds(criteria.AccountId)
                   .WhereByKeywords(criteria?.Keywords?.Trim())
                   .WhereByStatus(criteria.Status)
                   .WhereByType(criteria.Type)
                   .ToAreaAccountDto()
                   .OrderByDescending(x => x.CreatedTime)
                   .ToPageResult1(criteria.PageIndex, criteria.PageSize);

                var idList = result.Rows.Select(x => x.Id).ToList();

                var projectList = repository.IQueryable<DP_Project>().WhereByAuditIdList(idList);
                var accountList = repository.IQueryable<Account>().WhereByType(AccountType.质监员帐号);

                foreach (var item in result.Rows)
                {
                    item.ProjectCount = projectList.Count(x => x.AreaId == item.Id && (x.ChildCode == null || x.ChildCode.Trim() == string.Empty));
                    item.AccountCount = accountList.Count(x => x.Number.IndexOf(item.Number) == 0);
                }
                return new Tuple<int, IPagedList<AreaAccountDto>>(GetAccountCountByType(criteria, repository), result);
            }
        }

        ///获取用户分页数据集合
        public Tuple<int, IPagedList<AccountDto>> GetAccountPagedList(AccountCriteria criteria)
        {
            using (var repository = Ioc.Resolve<IRepositoryBase>())
            {
                var result = repository.IQueryable<Account>()
                    .WhereByAccountIds(criteria.AccountId)
                    .WhereByKeywords(criteria?.Keywords?.Trim())
                    .WhereByStatus(criteria.Status)
                    .WhereByType(criteria.Type)
                    .ToDto()
                    .OrderByDescending(x => x.CreatedTime)
                    .ToPageResult1(criteria.PageIndex, criteria.PageSize);

                return new Tuple<int, IPagedList<AccountDto>>(GetAccountCountByType(criteria, repository), result);
            }
        }

        ///获取帐号集合
        public IList<AccountDto> GetAccountList(AccountCriteria criteria)
        {
            using (var repository = Ioc.Resolve<IRepositoryBase<Account>>())
            {
                return repository.IQueryable()
                    .WhereByAccountIds(criteria.AccountId)
                    .WhereByAccountIdList(criteria.IdList)
                    .WhereByKeywords(criteria?.Keywords?.Trim())
                    .WhereByStatus(criteria.Status)
                    .WhereByType(criteria.Type)
                    .ToDto()
                    .OrderByDescending(x => x.CreatedTime).ToList();
            }
        }

        ///创建账号（审核、企业、项目）
        public AccountDto CreateAccount(AccountDto dto, Guid areaId)
        {
            using (var repository = Ioc.Resolve<IRepositoryBase>())
            {
                if (string.IsNullOrWhiteSpace(dto.Number))
                    throw new KnownException("帐号不能为空，请重新输入");

                var account = repository.FindEntity<Account>(x => x.Number == dto.Number.Trim());

                if (account.IsNull())
                {//创建项目帐号
                    account = dto.Merge<AccountDto, Account>();
                    account.Id = Guid.NewGuid();
                    account.Name = dto.Name.Trim();
                    account.Number = dto.Number.Trim();
                    account.Position = dto.Position.Trim();
                    account.PhoneNumber = dto.PhoneNumber?.Trim();
                    account.Password = dto.Number.ToMD5();//初始时和帐号一样，用户第一次登录时会强制修改密码
                    account.AccountIds = CurrentSession.AccountId.ToString();//关联审核人与项目帐号
                    account.CreatedTime = DateTime.Now;
                    if (repository.Insert(account) > 0)
                    {
                        if (dto.Type == AccountType.企业帐号) companyList = null;//添加企业帐号成功后，清空当前缓存，下次获取最新
                    }
                }
                else
                {//帐号已存在，建立关联
                    var accountIds = account.AccountIds?.Split(",").ToList();
                    if (accountIds == null) accountIds = new List<string>();
                    if (!accountIds.Contains(CurrentSession.AccountId.ToString()))
                    {
                        accountIds.Add(CurrentSession.AccountId.ToString());
                        account.AccountIds = string.Join(",", accountIds);
                        repository.Update(account);
                    }
                }

                if (dto.Type == AccountType.项目帐号)//当前流程中企业不能创建项目帐号
                {
                    //判断项目帐号对应的项目是否存在
                    var project = repository.FindEntity<DP_Project>(x => x.Code == account.Number);
                    var areaAccount = repository.FindEntity<Account>(areaId);
                    if (areaAccount.IsNull()) throw new KnownException("区域不存在");
                    if (project.IsNull())
                    {
                        project = new DP_Project
                        {
                            Id = Guid.NewGuid(),
                            Name = account.Name,
                            Code = account.Number,
                            //BuilderUnitNames = string.Empty,
                            IsBIM = false,
                            Area = areaAccount.Name,
                            AreaId = areaAccount.Id,
                            Status = AuditStatus.未报审,
                            AuditId = CurrentSession.AccountId,
                            AuditName = CurrentSession.AccountName,
                            CreatedTime = DateTime.Now
                        };
                        repository.Insert(project);//1.创建项目
                    }
                }

                //else if (dto.Type == AccountType.企业帐号)
                //{
                //    if (account.IsNull())
                //    {
                //        account = dto.Merge<AccountDto, Account>();
                //        account.Id = Guid.NewGuid();
                //        account.Name = dto.Name.Trim();
                //        account.Number = dto.Number.Trim();
                //        account.Password = dto.Number.ToMD5();//初始时和帐号一样，用户第一次登录时会强制修改密码
                //        account.AccountIds = CurrentSession.AccountId.ToString();
                //        account.CreatedTime = DateTime.Now;

                //        repository.Insert(account);
                //    }
                //    else
                //    {
                //        var accountIds = account.AccountIds.Split(",").ToList();
                //        accountIds.Add(CurrentSession.AccountId.ToString());
                //        account.AccountIds = string.Join(",", accountIds);
                //    }
                //}
                return dto;
            }
        }

        ///修改密码
        public bool ChangePassword(Guid accountId, string password)
        {
            using (var repository = Ioc.Resolve<IRepositoryBase<Account>>())
            {
                var entity = repository.FindEntity(accountId);

                if (entity.IsNull()) throw new KnownException("帐号不存在");
                if (entity.Password == password.ToMD5())
                    throw new KnownException("新密码不能与当前密码相同");

                entity.Password = password.ToMD5();

                return repository.Update(entity) > 0;
            }
        }

        ///修改帐号名称
        public bool ChangeAccountName(Guid accountId, string name)
        {
            using (var repository = Ioc.Resolve<IRepositoryBase<Account>>())
            {
                var entity = repository.FindEntity(accountId);
                if (entity.IsNull()) throw new KnownException("帐号不存在");

                entity.Name = name.Trim();

                return repository.Update(entity) > 0;
            }
        }

        ///修改帐号状态
        public bool ChangeAccountStatus(Guid accountId, string remark)
        {
            using (var repository = Ioc.Resolve<IRepositoryBase<Account>>())
            {
                var entity = repository.FindEntity(accountId);
                if (entity.IsNull()) throw new KnownException("帐号不存在");

                entity.Status = entity.Status == 1 ? 2 : 1;
                entity.Remark = remark;

                return repository.Update(entity) > 0;
            }
        }

        ///重置密码为帐号（通过AccountId）
        public bool ResetPasswordById(Guid accountId)
        {
            using (var repository = Ioc.Resolve<IRepositoryBase<Account>>())
            {
                var entity = repository.FindEntity(accountId);
                if (entity.IsNull()) throw new KnownException("帐号不存在");

                entity.Password = entity.Number.ToMD5();

                return repository.Update(entity) > 0;
            }
        }

        ///重置密码为帐号（通过Number）
        public bool ResetPasswordByNumber(string number)
        {
            using (var repository = Ioc.Resolve<IRepositoryBase<Account>>())
            {
                var entity = repository.FindEntity(x => x.Number == number.Trim());
                if (entity.IsNull()) throw new KnownException("帐号不存在");

                entity.Password = entity.Number.ToMD5();

                return repository.Update(entity) > 0;
            }
        }

        ///退出
        public void Logout(string token)
        {
            var current = Ioc.Resolve<IOperatorProvider>();
            if (current.GetCurrent() == null) return;
            using (var repository = Ioc.Resolve<IRepositoryBase<Sys_Session>>())
            {
                var entity = repository.FindEntity(x => x.Token == token.Trim());// && x.ExpiredTime > DateTime.Now
                entity.ExpiredTime = DateTime.Now.AddMinutes(-1);
                if (repository.Update(entity) > 0)
                    current.RemoveCurrent();
            }
        }

        ///获取帐号登录日志 分页数据集合
        public IPagedList<LoggingDto> GetLoggingPagedList(LoggingCriteria criteria)
        {
            using (var repository = Ioc.Resolve<IRepositoryBase<Sys_Logging>>())
            {
                return repository.IQueryable()
                    .WhereByKeywords(criteria?.Keywords?.Trim())
                    .WhereByAccountId(criteria.AccountId)
                    .WhereByAccountIdList(criteria.AccountIdList)
                    .ToDto()
                    .OrderByDescending(x => x.CreatedTime)
                    .ToPageResult1(criteria.PageIndex, criteria.PageSize);
            }
        }

        private int GetAccountCountByType(AccountCriteria criteria, IRepositoryBase repository)
        {
            return repository.IQueryable<Account>()
                    .WhereByStatus(2)
                    .WhereByKeywords(criteria?.Keywords?.Trim())
                    .WhereByAccountIds(criteria.AccountId)
                    .WhereByType(criteria.Type)
                    .Count();
        }

        ///获取帐号最后登录时间
        private DateTime GetLastlogintimeByAccountId(Guid accountId, IRepositoryBase repository = null)
        {
            if (repository == null) repository = Ioc.Resolve<IRepositoryBase>();
            using (repository)
            {
                var query = repository.IQueryable<Sys_Logging>().WhereByAccountId(accountId).Take(1).OrderByDescending(x => x.CreatedTime).ToList();
                if (query.Any())
                {
                    return query.FirstOrDefault().CreatedTime;
                }
                return DateTimeHelper.MinDateTime;
            }
        }

        ///新增登录日志
        private void AddLogging(Account entity, LoginStatus status = LoginStatus.成功, string descr = "登录成功")
        {
            try
            {
                if (SystemHelper.GetFirstMacAddress() == "E03F490F2A77") return;//本机调试时，不记登录日志

                var context = HttpContext.Current;
                var iPAddress = SystemHelper.GetUserHostAddress();
                var userAgent = context.Request.UserAgent;
                AddLogging(new Sys_Logging
                {
                    AccountId = entity.Id,
                    AccountName = entity.Name,
                    AccountNumber = entity.Number,
                    IPAddress = iPAddress,
                    UserAgent = userAgent,
                    Status = status,
                    Descr = descr
                });
            }
            catch (Exception)
            {

            }
        }

        ///新增登录日志
        private void AddLogging(Sys_Logging entity, IRepositoryBase repository = null)
        {
            if (repository == null) repository = Ioc.Resolve<IRepositoryBase>();
            using (repository)
            {
                entity.Id = Guid.NewGuid();
                entity.CreatedTime = DateTime.Now;
                repository.Insert(entity);
            }
        }

        private OperatorModel BuildOperator(Account entity)
        {
            var oper = new OperatorModel()
            {
                Id = entity.Id,
                ExpiredTime = DateTime.Now.AddMinutes(Configs.Instance.SessionExpireMinute),
                IsSystem = true,
                LoginTime = DateTime.Now,
                UserName = entity.Name,
                RoleIds = new List<Guid>()
            };
            Ioc.Resolve<IOperatorProvider>().AddCurrent(oper);

            return oper;
        }

        #region 会话 Session 

        ///清理过期 Session
        public void ClearExpireSession()
        {
            using (var repository = Ioc.Resolve<IRepositoryBase>())
            {
                //获取过期 Session 
                var list = repository.IQueryable<Sys_Session>().WhereByExpire().ToList();
                if (list != null && list.Count > 0)
                {
                    repository.BeginTrans();
                    foreach (var item in list)
                    {
                        repository.Delete(item);
                    }
                    repository.Commit();
                }
            }
        }

        #endregion

        #endregion

        #region 角色相关

        ///获取模块（菜单）分页数据集合
        public IPagedList<ModulesDto> GetModulesPagedList(ModulesCriteria criteria)
        {
            using (var repository = Ioc.Resolve<IRepositoryBase<Sys_Modules>>())
            {
                return repository.IQueryable()
                    .WhereByKeywords(criteria?.Keywords?.Trim())
                    .WhereByStatus(criteria.Status)
                    .WhereByCode(criteria.Code)
                    .ToDto()
                    .OrderByDescending(x => x.CreatedTime)
                    .ToPageResult1(criteria.PageIndex, criteria.PageSize);
            }
        }


        #endregion
    }
}
